pub mod euclidean;
// pub mod kmeans;
use serde::Deserialize;
use serde::Serialize;
use std::time::SystemTime;
use std::time::UNIX_EPOCH;

pub fn add(left: usize, right: usize) -> usize {
    left + right
}
use chrono::DateTime;
use chrono::Utc;
use rand::rngs::ThreadRng;
use rand::Rng;
use std::fmt::Write;

type Percentage = f64;

/// MA: Moving Average
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
pub struct MA {
    pub date: DateTime<Utc>,
    pub price: f64,
    pub slope: Percentage,
}

impl MA {
    // Function to calculate the Moving Average (MA) slopes
    pub fn calculate_ma_slopes(ma_data: &mut Vec<MA>, period: usize) {
        // Set the slope for the first `period - 1` items to the initial slope
        for ma in &mut ma_data[0..period - 1] {
            ma.slope = 0.0;
        }

        // Calculate the slope for the remaining items
        for i in ((period - 1)..ma_data.len()).rev() {
            let current_price = ma_data[i].price;
            let previous_price = ma_data[i + 1 - period].price;
            let slope = ((current_price - previous_price) / previous_price) * 100.0;
            ma_data[i].slope = slope;
        }
    }

    /// return (highest_before,lowest, highest_after, max_value)
    pub fn find_before_lowest_after(prices: &Vec<MA>) -> (MA, MA, MA, f64) {
        let lowest = prices
            .iter()
            .min_by_key(|p| (p.price * 1000f64) as u64)
            .unwrap()
            .clone();
        let mut highest_before = lowest.clone();
        let mut highest_after = lowest.clone();

        for price in prices.iter().filter(|p| p.date < lowest.date) {
            if price.price > highest_before.price {
                highest_before = price.clone();
            }
        }

        for price in prices.iter().filter(|p| p.date > lowest.date) {
            if price.price > highest_after.price {
                highest_after = price.clone();
            }
        }

        (
            highest_before.to_owned(),
            lowest.to_owned(),
            highest_after.to_owned(),
            if highest_after.price > highest_before.price {
                highest_after.price
            } else {
                highest_before.price
            },
        )
    }

    /// return (lowest_before,highest, lowest_after)
    pub fn find_before_highest_after(prices: &Vec<MA>) -> (MA, MA, MA) {
        let highest = prices
            .iter()
            .max_by_key(|p| (p.price * 1000f64) as u64)
            .unwrap()
            .clone();
        let mut lowest_before = highest.clone();
        let mut lowest_after = highest.clone();

        for price in prices.iter().filter(|p| p.date < highest.date) {
            if price.price < lowest_before.price {
                lowest_before = price.clone();
            }
        }

        for price in prices.iter().filter(|p| p.date > highest.date) {
            if price.price < lowest_after.price {
                lowest_after = price.clone();
            }
        }

        (
            lowest_before.to_owned(),
            highest.to_owned(),
            lowest_after.to_owned(),
        )
    }
}

/// Mill-Seconds after 1970-01-01 00:00:00 UTC
pub fn duration_ms_since_epoch() -> u64 {
    (SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_secs_f64()
        * 1000.0) as u64
}

/// random hex string
pub fn generate_random_hex_string(length: usize) -> String {
    let mut rng = ThreadRng::default();
    let mut result = String::with_capacity(length);
    for _ in 0..length {
        // 生成一个 0-15 的随机数，代表十六进制的一个字符
        let random_byte = rng.gen_range(0..=15);
        // 将随机数转换为十六进制字符并写入结果字符串
        write!(&mut result, "{:01x}", random_byte).expect("Failed to write to string");
    }
    result
}

#[cfg(test)]
mod tests {
    use chrono::TimeZone;
    use toml::value::DatetimeParseError;

    use super::*;

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }

    #[test]
    fn test_generate_random_hex_string() {
        let uuid_like_string = generate_random_hex_string(32);
        println!("{}", uuid_like_string);
    }

    #[test]
    fn test_find_before_lowest_after() {
        let prices = [
            MA {
                date: dateparser::parse("2024-02-23T00:00:00Z").unwrap(),
                price: 0.6,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-22T00:00:00Z").unwrap(),
                price: 0.7,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-21T00:00:00Z").unwrap(),
                price: 0.5,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-20T00:00:00Z").unwrap(),
                price: 0.4,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-19T00:00:00Z").unwrap(),
                price: 0.3,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-08T00:00:00Z").unwrap(),
                price: 0.6,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-07T00:00:00Z").unwrap(),
                price: 0.8,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-06T00:00:00Z").unwrap(),
                price: 0.9,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-05T00:00:00Z").unwrap(),
                price: 0.5,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-02T00:00:00Z").unwrap(),
                price: 0.6,
                ..Default::default()
            },
        ];

        let b_l_a = MA::find_before_lowest_after(&Vec::from(prices));
        assert_eq!(0.9, b_l_a.0.price);
        assert_eq!(0.3, b_l_a.1.price);
        assert_eq!(0.7, b_l_a.2.price);
    }

    #[test]
    fn test_find_before_highest_after() {
        let prices = [
            MA {
                date: dateparser::parse("2024-02-23T00:00:00Z").unwrap(),
                price: 116.0,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-22T00:00:00Z").unwrap(),
                price: 127.0,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-21T00:00:00Z").unwrap(),
                price: 135.0,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-20T00:00:00Z").unwrap(),
                price: 144.0,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-19T00:00:00Z").unwrap(),
                price: 103.0,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-08T00:00:00Z").unwrap(),
                price: 116.0,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-07T00:00:00Z").unwrap(),
                price: 128.0,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-06T00:00:00Z").unwrap(),
                price: 109.0,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-05T00:00:00Z").unwrap(),
                price: 105.0,
                ..Default::default()
            },
            MA {
                date: dateparser::parse("2024-02-02T00:00:00Z").unwrap(),
                price: 106.0,
                ..Default::default()
            },
        ];

        let mut prices = Vec::from(prices);
        prices.reverse();

        MA::calculate_ma_slopes(&mut prices, 5);
        prices.reverse();

        for p in &prices {
            println!("{:?}", p);
        }

        let b_h_a = MA::find_before_highest_after(&Vec::from(prices));
        assert_eq!(103.0, b_h_a.0.price);
        assert_eq!(144.0, b_h_a.1.price);
        assert_eq!(116.0, b_h_a.2.price);
    }
}
